﻿//#define TEST

using System;
using System.Diagnostics;
using System.IO;
using LLoger;
using OpenPop.Mime;
using TSRepLoader.Properties;
using Ionic.Zip;
using OpenPop.Mime.Header;


namespace TSRepLoader
{
    class MicexDownloader : MailDownloader
    {
        private Settings _sett = Properties.Settings.Default;

        public MicexDownloader(string host, int port, bool ssl, string user, string pass, ILogWriter log)
            : base(host, port, ssl, user, pass, log)
        {
            CheckAndCreatePath(_sett.MicexRepPath);
        }

        public override void Load(DateTime date)
        {
            var subjs = _sett.MicexSubj.Split(';');
            if (subjs.Length == 1)
            {
                Load(date, null, _sett.MicexSubj, _sett.MicexSign);
                return; 
            }

            if (subjs.Length > 1)
                foreach (var subj in subjs)
                {
                    Load(date, null, subj, _sett.MicexSign);
                }
        }

        protected override bool HandleAttachment(string savedFile, MessageHeader subject = null)
        {
            if (!File.Exists(savedFile))
            {
                _log.WriteLine("ERROR: Attachment file was not found " + savedFile);
                return false;
            }

            try
            {
                var res = HandleReport(ref savedFile);

                return res;
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "WARNING: An XML-report not found. File " + savedFile);
                return false;
            }
        }

        /// <summary>
        /// Обработка отчета: расшифровка, проверка подписи, раззиповка
        /// </summary>
        /// <param name="savedFile"></param>
        /// <returns></returns>
        private bool HandleReport(ref string savedFile)
        {
            if (!File.Exists(savedFile))
            {
                _log.WriteLine("ERROR: source file {0} not found", savedFile);
                return false;
            }

            if (Path.GetExtension(savedFile).ToLower().Equals(".xml"))
            {
                SaveToTargetPath(savedFile);
                return true;
            }

            bool res = HadleZip(ref savedFile) || HadleP7e(ref savedFile) || HadleP7s(ref savedFile);

            if (res)
                res = HandleReport(ref savedFile);



            return res;
        }

        /// <summary>
        /// Обработка подписей отчета
        /// </summary>
        /// <param name="savedFile"></param>
        /// <returns></returns>
        private bool HadleP7s(ref string savedFile)
        {
            try
            {
                var ext = ".p7s";
                var tmpExt = Path.GetExtension(savedFile);
                if (!string.IsNullOrWhiteSpace(tmpExt) && tmpExt.ToLower().Equals(ext))
                {
                    var tmp = savedFile.Replace(ext, "");

                    var cmd = _sett.p7sCommand.Split(';');
                    StartExternalProcess(cmd[0], string.Format(cmd[1], savedFile, tmp));

                    _log.WriteLine(savedFile + " was verified and saved to " + Path.GetDirectoryName(tmp));

                    savedFile = tmp;
                    return true;
                }
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "ERROR: Problem with file handling " + savedFile);
            }

            return false;

        }

        /// <summary>
        /// Расшифровка отчета
        /// </summary>
        /// <param name="savedFile"></param>
        /// <returns></returns>
        private bool HadleP7e(ref string savedFile)
        {
            try
            {
                var ext = ".p7e";
                var tmpExt = Path.GetExtension(savedFile);
                if (!string.IsNullOrWhiteSpace(tmpExt) && tmpExt.ToLower().Equals(ext))
                {
                    var tmp = savedFile.Replace(ext, "");

                    var cmd = _sett.p7eCommand.Split(';');
                    StartExternalProcess(cmd[0], string.Format(cmd[1], savedFile, tmp));
                    
                    _log.WriteLine(savedFile + " was decripted to " + Path.GetDirectoryName(tmp));

                    savedFile = tmp;

                    return true;
                }
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "ERROR: Problem with file handling " + savedFile);
            }


            return false;
        }

        private void StartExternalProcess(string extCmd, string args)
        {
            try
            {
                Process process = new Process
                    {
                        StartInfo =
                            {
                                FileName = extCmd,
                                Arguments = args
                            }
                    };

                process.EnableRaisingEvents = true;
                process.Exited += new EventHandler(process_Exited);

                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.UseShellExecute = false;
                process.Start();

                if (process.Id != -1)
                    process.WaitForExit();

                if (process.ExitCode != 0)
                    throw new Exception("process exited with code " + process.ExitCode);

            }
            catch (Exception ex)
            {
                throw new Exception("ERROR: error occured while external process starting " + extCmd + " " + ex.Message, ex);
            }

        }

        void process_Exited(object sender, EventArgs e)
        {
            var procc = ((Process)sender);
            string procResMsg = procc.StandardOutput.ReadToEnd();
            if (procResMsg != string.Empty)
            {
                _log.WriteLine(procc.StartInfo.FileName + " " + procc.StartInfo.Arguments + "\r\nPROCESS: With Exit code " + procc.ExitCode + ", Message:" + procResMsg);
            }
        }

        /// <summary>
        /// Распаковка зип-архива
        /// </summary>
        /// <param name="savedFile"></param>
        /// <returns></returns>
        private bool HadleZip(ref string savedFile)
        {
            try
            {
                var ext = ".zip";
                var tmpExt = Path.GetExtension(savedFile);
                if (!string.IsNullOrWhiteSpace(tmpExt) && tmpExt.ToLower().Equals(ext))
                {
                    var tmp = savedFile.Replace(ext, "");

                    (new ZipFile(savedFile)).ExtractAll(DownloadFolder);
                    
                    _log.WriteLine(savedFile + " was unZipped to " + Path.GetDirectoryName(tmp));

                    savedFile = tmp;
                    return true;
                }
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "ERROR: Problem with file handling " + savedFile);
            }


            return false;
        }

        private void SaveToTargetPath(string savedFile)
        {
            if (!File.Exists(savedFile))
            {
                _log.WriteLine("ERROR: Attachment file was not found " + savedFile);
            }

            string path = Path.Combine(_sett.MicexRepPath, LoadDate.ToString("yyyy"),
                LoadDate.ToString("MM"));

            try
            {
                CheckAndCreatePath(path);

                path = Path.Combine(path, Path.GetFileName(savedFile));

                File.Copy(savedFile, path);

                _log.WriteLine("Attachement was saved to final path " + path);
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "ERROR: Unable to save hanled report to " + savedFile);
            }
        }

        protected override string SaveToFile(MessagePart attachment, MessageHeader subject = null)
        {
            try
            {
                string path = Path.Combine(DownloadFolder, attachment.FileName);
                attachment.Save(new FileInfo(path));

                return path;
            }
            catch (Exception ex)
            {
                _log.WriteLine(ex, "ERROR: Unaable to save attachment file");
            }

            return "";
        }
    }


}